package net.lee.springbootvertx.vertx.route;


import io.vertx.core.http.HttpMethod;
import io.vertx.rxjava.core.Vertx;
import io.vertx.rxjava.ext.web.Router;
import net.lee.springbootvertx.vertx.request.Controller;
import net.lee.springbootvertx.vertx.request.RequestMapping;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Component
public class RouteMapping implements ApplicationContextAware {

    ApplicationContext context;

    private Router router;

    public void init(Vertx vertx) {
        router = Router.router(vertx);
        String[] beanNames =  context.getBeanNamesForAnnotation(Controller.class);
        for (String beanName : beanNames
                ) {
            Object controller = context.getBean(beanName);
            Annotation[] annotations = controller.getClass().getAnnotations();
            List<String> classPathMapping = new ArrayList<>();
            for (Annotation annotation : annotations
                    ) {
                if (annotation instanceof RequestMapping) {
                    String[] path = ((RequestMapping) annotation).value();
                    if (path != null && path.length > 0) {
                        for (String pathInfo : path
                                ) {
                            classPathMapping.add(pathInfo);
                        }
                    }
                    break;
                }
            }
            Method[] methods = controller.getClass().getMethods();
            for (Method method : methods
                    ) {
                Annotation[] methodAnnotations = method.getAnnotations();
                for (Annotation methodAnnotation : methodAnnotations
                        ) {
                    if (methodAnnotation instanceof RequestMapping) {
                        String[] path = ((RequestMapping) methodAnnotation).value();
                        if (path != null && path.length > 0) {
                            if (classPathMapping != null && classPathMapping.size() > 0) {
                                for (String classRequestMapping : classPathMapping
                                        ) {
                                    for (String methodRequestMapping : path
                                            ) {
                                        HttpMethod[] requestMethods = ((RequestMapping) methodAnnotation).requestMethod();
                                        for (HttpMethod requestMethod : requestMethods
                                                ) {
                                            router.route(requestMethod, classRequestMapping + methodRequestMapping).handler(rc -> {
                                                try {
                                                    method.invoke(controller, rc);
                                                } catch (IllegalAccessException e) {
                                                    e.printStackTrace();
                                                } catch (InvocationTargetException e) {
                                                    e.printStackTrace();
                                                }
                                            });
                                        }
                                    }
                                }
                            } else {
                                for (String methodRequestMapping : path
                                        ) {
                                    HttpMethod[] requestMethods = ((RequestMapping) methodAnnotation).requestMethod();
                                    for (HttpMethod requestMethod : requestMethods
                                            ) {
                                        router.route(requestMethod, methodRequestMapping).handler(rc -> {
                                            try {
                                                method.invoke(controller, rc);
                                            } catch (IllegalAccessException e) {
                                                e.printStackTrace();
                                            } catch (InvocationTargetException e) {
                                                e.printStackTrace();
                                            }
                                        });
                                    }
                                }
                            }
                        }
                        break;
                    }
                }
            }
        }
    }

    public Router getRouter() {
        return router;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }
}
